package it.asvp.asvp_portal.service.services.impl;

import it.asvp.asvp_portal.asvp_util.enumerative.RoleName;
import it.asvp.asvp_portal.asvp_util.util.DateUtils;
import it.asvp.asvp_portal.data.dao.AddressDao;
import it.asvp.asvp_portal.data.dao.MemberAccountDao;
import it.asvp.asvp_portal.data.dao.MemberDao;
import it.asvp.asvp_portal.data.dao.RoleDao;
import it.asvp.asvp_portal.data.entity.domain.Address;
import it.asvp.asvp_portal.data.entity.member.Member;
import it.asvp.asvp_portal.data.entity.member.MemberAccount;
import it.asvp.asvp_portal.data.entity.member.Role;
import it.asvp.asvp_portal.service.services.MemberAccountService;
import it.asvp.asvp_portal.service.services.MemberService;
import it.asvp.asvp_portal.service.util.Operation;
import it.asvp.asvp_portal.service.util.Permission;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MemberServiceImpl implements MemberService {
  @Autowired
  RoleDao              roleDao;
  @Autowired
  MemberDao            memberDao;
  @Autowired
  AddressDao           addressDao;
  @Autowired
  MemberAccountDao     memberAccountDao;
  @Autowired
  MemberAccountService memberAccountService;

  // FIXME: segnalazione mail
  @Override
  @Transactional
  @Rollback
  public void createMember(Long idCurrentAccount, Member transientMember, MemberAccount transientAccount, RoleName roleName) throws Exception {

    Role roleMax = Role.getMax(memberAccountService.getRoles(idCurrentAccount));
    Role roleToAdd = roleDao.findByRoleName(roleName);

    if (!Permission.checkPermission(roleMax, roleToAdd, Operation.CREATE)) {
      throw new Exception("non possiede i diritti necessari per aggiungere questo permesso");
    }

    if ((memberDao.findByEmail(transientMember.getEmail()) != null) || (memberDao.findByFiscalCode(transientMember.getFiscalCode()) != null)) {
      throw new Exception("Member gia' esistente");
    }

    Long idAddress = addressDao.persist(transientMember.getAddress()).getId();
    transientMember.setAddress(addressDao.get(idAddress));
    Long id = memberDao.persist(transientMember);
    transientAccount.setMember(memberDao.findById(id));
    memberAccountService.createAccount(idCurrentAccount, transientAccount, roleName);
  }

  @Override
  @Transactional
  public void updateMember(Long idCurrentAccount, Long idMemberToUpdate, Member newMemberData) throws Exception {

    MemberAccount persistentMemberAccount = memberAccountDao.findById(idCurrentAccount);
    Member persistentMemberToUpdate = memberDao.findById(idMemberToUpdate);

    if (persistentMemberAccount == null) {
      throw new Exception("account non esistente");
    }

    if (persistentMemberToUpdate == null) {
      throw new Exception("socio da aggiornare non esistente");
    }

    MemberAccount accountToUpdate = memberAccountService.getAccountByMemberId(persistentMemberToUpdate.getId());
    Role roleMax1 = Role.getMax(memberAccountService.getRoles(persistentMemberAccount.getId()));
    Role roleMax2 = Role.getMax(memberAccountService.getRoles(accountToUpdate.getId()));

    if (!Permission.checkPermission(roleMax1, roleMax2, Operation.UPDATE)) {
      throw new Exception("non possiede i diritti necessari per aggiornare questi dati");
    }

    Address persistentAddress = persistentMemberToUpdate.getAddress();
    persistentAddress.setCity(newMemberData.getAddress().getCity());
    persistentAddress.setCivicNumber(newMemberData.getAddress().getCivicNumber());
    persistentAddress.setLastUpdate(DateUtils.getCurrentDate());
    persistentAddress.setPostalCode(newMemberData.getAddress().getPostalCode());
    persistentAddress.setProvince(newMemberData.getAddress().getProvince());
    persistentAddress.setStreet(newMemberData.getAddress().getStreet());

    persistentMemberToUpdate.setAddress(persistentAddress);
    persistentMemberToUpdate.setBirthDate(newMemberData.getBirthDate());
    persistentMemberToUpdate.setEmail(newMemberData.getEmail());
    persistentMemberToUpdate.setFirstName(newMemberData.getFirstName());
    persistentMemberToUpdate.setFiscalCode(newMemberData.getFiscalCode());
    persistentMemberToUpdate.setLastName(newMemberData.getLastName());
    persistentMemberToUpdate.setLastUpdate(DateUtils.getCurrentDate());
    persistentMemberToUpdate.setNationality(newMemberData.getNationality());
    persistentMemberToUpdate.setPhone(newMemberData.getPhone());
    persistentMemberToUpdate.setSchool(newMemberData.getSchool());
    persistentMemberToUpdate.setSex(newMemberData.getSex());

    memberDao.merge(persistentMemberToUpdate);
  }

  @Override
  @Transactional
  public void deleteMember(Long idCurrentAccount, Long idMemberToDelete) throws Exception {

    MemberAccount persistentMemberAccount = memberAccountDao.findById(idCurrentAccount);
    Member persistentMemberToDelete = memberDao.findById(idMemberToDelete);

    if (persistentMemberAccount == null) {
      throw new Exception("account non esistente");
    }

    if (persistentMemberToDelete == null) {
      throw new Exception("socio da cancellare non esistente");
    }

    MemberAccount accountToDelete = memberAccountService.getAccountByMemberId(idMemberToDelete);
    Role roleMax1 = Role.getMax(memberAccountService.getRoles(persistentMemberAccount.getId()));
    Role roleMax2 = Role.getMax(memberAccountService.getRoles(accountToDelete.getId()));

    if (!Permission.checkPermission(roleMax1, roleMax2, Operation.DELETE)) {
      throw new Exception("non possiede i diritti necessari per aggiungere questo permesso");
    }

    memberDao.delete(persistentMemberToDelete);
  }

  @Override
  @Transactional
  public Member getMember(Long idCurrentAccount, Long idMemberToRead) throws Exception {

    MemberAccount persistentMemberAccount = memberAccountDao.findById(idCurrentAccount);
    Member persistentMemberToRead = memberDao.findById(idMemberToRead);

    if (persistentMemberAccount == null) {
      throw new Exception("account non esistente");
    }

    if (persistentMemberToRead == null) {
      throw new Exception("socio da visualizzare non esistente");
    }

    MemberAccount accountToRead = memberAccountService.getAccountByMemberId(persistentMemberToRead.getId());
    Role roleMax1 = Role.getMax(memberAccountService.getRoles(persistentMemberAccount.getId()));
    Role roleMax2 = Role.getMax(memberAccountService.getRoles(accountToRead.getId()));

    if (!Permission.checkPermission(roleMax1, roleMax2, Operation.READ)) {
      throw new Exception("non possiede i diritti necessari per visualizzare questi dati");
    }

    return persistentMemberToRead;
  }

  @Override
  @Transactional
  public Member getMemberById(Long id) throws Exception {
    Member member = memberDao.findById(id);
    if (member == null) {
      throw new Exception("Socio non esistente");
    }
    return member;
  }

  @Override
  @Transactional
  public Member getMemberByEmail(String email) throws Exception {
    Member member = memberDao.findByEmail(email);
    if (member == null) {
      throw new Exception("Socio non esistente");
    }
    return member;
  }

}
